package acptTests;

import java.util.Vector;

import msgParser.Strings;

import org.junit.Before;
import org.junit.Test;

import forumSystem.Forum;
import forumSystem.ForumSystemImpl;
import forumSystem.Post;
import forumSystem.Reply;
import forumSystem.SubForum;
import forumSystem.User;

import reactor.Reactor;
import tokenizer.StringMessage;

public class DBTest extends ServerTest{
	
	protected final int adminID = 1;
	protected int modID;
	protected int userID;
	
	protected int ForumID;
	protected int SubForumID;
	protected int TopicID;
	protected int ReplyID;
	
	protected String Policies = Strings.IMMEDIATE_NOTIFY+"\0" + Strings.FORUM_MEMBERS_NOTIFY +"\0"+ 1 +"\0" +Strings.AUTHOR_FORUM_DELETE_POST+"\0"
			  +Strings.MIN_POST_ADD_MODERATOR+"\0"+Strings.CANNOT_REMOVE_SINGLE_MODERATOR+"\0"+ 
	Strings.VALID_EMAIL_SECURITY+"\0" +Strings.REJECT_BAD_WORDS;
	
	protected String mail = "maximdzagoev@gmail.com";
	
	@Before
	public void setUp()
	{	
		super.setUp();
	}
	

	public String send(String str)
	{
		return sp.processMessage(new StringMessage(str) , ch).toString();
	}
	
	public void init()
	{
		send("INIT_FORUM \0 superAdmin \0 myPass");
	}
	
	public String loginSuperAdmin()
	{
		return send("ADMIN_LOGIN \0 superAdmin \0 myPass");
	}
	
	public String logout()
	{
		return send("LOGOUT");
	}
	
	public String loginUser(String user , String pass ,int forumID)
	{
		String result = send("LOG_IN \0 "+ user +" \0 "+ pass + " \0" + forumID);
		if (result.startsWith("LOGGED_IN"))
		userID = Integer.parseInt(getWord(result.toString(), 1));
		return result;
	}
	
	public String register(String user , String pass , int forumID)
	{
		String mail1 = mail+Math.random()*10000+"";
		String result = send("REGISTER \0 " + user + "\0 " + pass +" \0" + mail1 + "\0"+ forumID);
		if (result.startsWith("REGISTERED"))
		userID = Integer.parseInt(getWord(result.toString(), 1));
		return result;
	}
	
	public String addForum(String name , int AdminID)
	{
		return send("ADD_FORUM \0"+name+"\0"+AdminID+"\0"+Policies);
	}
	
	public String addSubForum(String name , int forumID , int ModID)
	{
		return send("ADD_SUBFORUM \0"+name+"\0"+forumID+"\0"+ModID);
	}
	public String addTopic(String title , String body , int subID)
	{
		return send("ADD_TOPIC \0"+title+"\0"+body+"\0"+subID);
	}
	public String addReply(String body ,  int topID)
	{
		return send("ADD_REPLY \0"+body+"\0"+topID);
	}
	public String editReply(String body ,  int repID)
	{
		return send("EDIT_REPLY \0"+body+"\0"+repID);
	}
	
	public String editPost(String body ,  int postID)
	{
		return send("EDIT_POST \0"+body+"\0"+postID);
	}
	
	public String addModerator(int userid , int subforumID)
	{
		return send("ADD_MODERATOR \0"+userid+"\0"+subforumID);
	}
	
	public String removeModerator(int userid , int subforumID)
	{
		return send("REMOVE_MODERATOR \0"+userid+"\0"+subforumID);
	}
	
	public String addAdmin(int userid , int forumID)
	{
		return send("ADD_ADMIN \0"+userid+"\0"+forumID);
	}
	
	public void register_login(String user, String pass , int forum)
	{
		register( user ,pass , forum);
		String User = loginUser( user ,pass , forum);
		userID = Integer.parseInt(getWord(User, 1));
	}
	
	public void init_forum_logout()
	{	
		init();
		loginSuperAdmin();
		int rand = (int) (Math.random() * 10000);
		String forum = addForum("Cars"+rand , adminID);
		ForumID = Integer.parseInt(getWord(forum, 1));
		logout();
	}
	
/******** Testing **********/
	
	@Test
	public void testLogout()
	{
		///No need.
	}
	
	@Test
	public void testLogin()
	{
		//No need.
	}
	
	@Test 
	public void testAddForum()
	{
		init_forum_logout();
		
		//super admin adds forum which wasn't exist: 
		String forumName = "Sea Food" + Math.random()*100 + "";
		boolean exists = false;
		
		Vector<Forum> ForumsList = Reactor.db.getForumlist();
		for (int i = 0; i < ForumsList.size(); i++)
		{
			if(ForumsList.elementAt(i).getName().equals(forumName))
				exists = true;
		}
		assertFalse(exists);
		
		loginSuperAdmin();
		String forum1 = addForum(forumName , userID);
		int fid = Integer.parseInt(getWord(forum1, 1));
		logout();
		
		if(!exists)
		{
			ForumsList = Reactor.db.getForumlist();
			
			for (int i = 0; i < ForumsList.size() && !exists; i++)
			{
				if(ForumsList.elementAt(i).getName().equals(forumName))
					exists = true;
			}
			assertTrue(exists);
		}
	}
	
	
	@Test
	public void testRegister()
	{
		init();
		
		//Guest
		String userName = "max" + Math.random()*10000 + "";
		Vector<User> users = Reactor.db.getUsers();
		
		int usersCount = users.size();
		boolean exists = false;
		
		for(User u: users)
		{
			if(u.getUsername().equals(userName))
				exists = true;
		}
		
		String ans1 = register(userName ,"1234" , ForumID);
		
		if(!exists && ans1.startsWith("REGISTERED"))
		{
			for (int i = 0; i < users.size() && !exists; i++)
			{
				if(users.elementAt(i).getUsername().equals(users))
					exists = true;
			}
			assertTrue(exists);
			assertTrue(usersCount == Reactor.db.getUsers().size()-1 );
		}
	}
	
	@Test
	public void testAddSubForum()
	{
		init_forum_logout();
		//cars forum exists.
		
		//user name:
		String userName = "max" + Math.random()*10000 + "";
		
		//register		
		String ans1 = register(userName ,"1234" , ForumID);
		//login admin
		loginSuperAdmin();
		
		//add Admin to the Forum
		int uid = Integer.parseInt(getWord(ans1, 1));
		addAdmin(uid, ForumID);
		logout();
		
		//login
		loginUser(userName ,"1234" , ForumID);
		//add subforum.
		addSubForum("Sea-Food-Places", ForumID, uid);
		
		//TESTS..
		Vector<SubForum> subs = Reactor.db.getSubForumslist(ForumID);
		int size = subs.size();
		
		String ans3 = addSubForum("Sea-Food-Places" , ForumID ,uid);
		
		if(ans3.startsWith("SUBFORUM_ADDED"))
		{
			subs = Reactor.db.getSubForumslist(ForumID);
			assertTrue(subs.size() == size+1);
			boolean exists = false;
			
			for(int i=0; i < subs.size() && !exists; i++)
			{
				if(subs.elementAt(i).getTitle().equals("Sea-Food-Places"))
					exists = true;
			}
			assertTrue(exists);
		}
		
		
		
	}
	

	@Test
	public void testAddTopic()
	{
		init_forum_logout();
		
		loginSuperAdmin();
		String subforum = addSubForum("Planes" , ForumID , adminID);
		SubForumID = Integer.parseInt(getWord(subforum, 1));
		logout();

		//user
		int size = Reactor.db.getForumPosts(ForumID).size();
		
		register_login( "max" ,"1234" , ForumID);//TODO
		String ans1 = addTopic("BMW" , "Engine type" , SubForumID);
		assertTrue(ans1.startsWith("TOPIC_ADDED"));
		logout();
		
		
		Vector<Post> topics= Reactor.db.getForumPosts(ForumID);
		
		assertTrue(topics.size() == size+1);
		
		boolean exists = false;
		for(int i=0; i<topics.size(); i++)
		{
			System.out.println("topic "+topics.elementAt(i).getTitle());
			if(topics.elementAt(i).getTitle().equals("BMW"))
				exists = true;
		}
		assertTrue(exists);
	}
	
	@Test
	public void testAddReply()
	{
		init_forum_logout();
		//infrastructure:
		loginSuperAdmin();
		String subforum = addSubForum("Planes" , ForumID , adminID);
		SubForumID = Integer.parseInt(getWord(subforum, 1));
		String topic = addTopic("title" , "body" ,SubForumID);
		TopicID = Integer.parseInt(getWord(topic, 1));
		logout();
		
		
		//user
		int size = Reactor.db.getPostReplies(TopicID).size();
		
		register_login( "max" ,"1234" , ForumID);
		String ans1 = addReply("Engine type" , TopicID);
		assertTrue(ans1.startsWith("REPLY_ADDED"));
		logout();
		
		Vector<Reply> replies= Reactor.db.getPostReplies(TopicID);
		
		assertTrue(replies.size() == size+1);
		
		boolean exists = false;
		for(int i=0; i<replies.size(); i++)
		{
			if(replies.elementAt(i).getContent().equals("Engine type"))
				exists = true;
		}
		assertTrue(exists);
	}

	@Test
	public void testShowForums()
	{
		init();
		
		loginSuperAdmin();
		//String subforum = addSubForum("Planes" , ForumID , adminID);
		//SubForumID = Integer.parseInt(getWord(subforum, 1));
		String forum1 = addForum("army", adminID);
		String forum2 = addForum("bgu" , adminID);
		String forum3 = addForum("sport", adminID);
		logout();
		
		String[] ans1 = send("SHOW_FORUMS").split("\0");
		Vector<String> names = new Vector<String>();
		
		for (int i = 1; i < ans1.length; i=i+2) {
			names.add(ans1[i]);
		}
		
		Vector<Forum> forumsList = Reactor.db.getForumlist();
		Vector<String> forumnames = new Vector<String>();
		
		for (int k=0; k<forumsList.size(); k++)
			forumnames.add(forumsList.elementAt(k).getName());
		
		for(String name: names)
		{
			System.out.println("name - " + name);
		}
		
		//all the names we added are in the DB.
		for(String name: names)
		{
			System.out.println("name - " + name);
			assertTrue(forumnames.contains(name));
		}
	}
	
	
	public void testShowSubForums()
	{
		init_forum_logout();
		
		loginSuperAdmin();
		
		int size = Reactor.db.getSubForumslist(ForumID).size();
		
		String subforum = addSubForum("Planes" , ForumID , adminID);
		String subforum2 = addSubForum("Bikes", ForumID, adminID);
		String subforum3 = addSubForum("Guys", ForumID, adminID);
		
		logout();
		
		String[] ans1 = send("SHOW_SUBFORUMS \0"+ ForumID).split("\0");
		Vector<String> names = new Vector<String>();
		
		for (int i = 1; i < ans1.length; i=i+2) {
			names.add(ans1[i]);
		}
		Vector<SubForum> forumsList = Reactor.db.getSubForumslist(ForumID);
		Vector<String> subforumnames  = new Vector<String>();
		
		for (int k=0; k<forumsList.size(); k++)
			subforumnames.add(forumsList.elementAt(k).getTitle());
		
		//all the names we added are in the DB.
		for(String name: names)
		{
			assertTrue(subforumnames.contains(name));
		}
		assertTrue(forumsList.size() == size + 3);
	}
	
	
	public void testShowTopics()
	{
		init_forum_logout();
		
		loginSuperAdmin();
		String subforum = addSubForum("Planes" , ForumID , adminID);
		SubForumID = Integer.parseInt(getWord(subforum, 1));
		
		int size = Reactor.db.getSubForumPosts(SubForumID).size();
		
		String topic  = addTopic("hey there","whats up with you?",SubForumID);
		String topic1 = addTopic("hey there","whats up with you?",SubForumID);
		String topic2 = addTopic("hey there","whats up with you?",SubForumID);
		
		logout();
		
		String[] ans1 = send("SHOW_TOPICS\0"+SubForumID).split("\0");
		Vector<String> names = new Vector<String>();
		
		for (int i = 1; i < ans1.length; i=i+2) {
			names.add(ans1[i]);
		}
		
		Vector<Post> postsList =  Reactor.db.getSubForumPosts(SubForumID);
		Vector<String> postsnames = new Vector<String>();
		
		for (int k=0; k<postsList.size(); k++)
			postsnames.add(postsList.elementAt(k).getTitle());
		//all the names we added are in the Forum.
		for(String name: names)
		{
			assertTrue(postsnames.contains(name));
		}
		assertTrue(postsList.size() == size + 3);
	}
	
	@Test
	public void testShowAllUsers()
	{
		//no permissions.
	}
	
	public void testRemoveTopic()
	{
		init_forum_logout();
		loginSuperAdmin();
		String subforum = addSubForum("Planes" , ForumID , adminID);
		SubForumID = Integer.parseInt(getWord(subforum, 1));
		String topic = addTopic("Can planes fly?","I wonder how",SubForumID);
		TopicID = Integer.parseInt(getWord(topic, 1));
		logout();
		
		Vector<Post> topics = Reactor.db.getForumPosts(ForumID);
		boolean exists = false;
		for (int i = 0; i < topics.size(); i++) 
		{
			if(TopicID == topics.elementAt(i).getId());
			exists = true;
		}
		assertTrue(exists);
		
		loginSuperAdmin();
		addModerator(userID , SubForumID);
	//	logout();
		//moderator
		loginUser( "max" ,"1234" , ForumID);
		String ans4 = send("REMOVE_TOPIC\0"+TopicID);
		System.out.println("---------");
		System.out.println(ans4);
		assertTrue(ans4.startsWith("TOPIC_REMOVED"));
		logout();
		
		topics = Reactor.db.getForumPosts(ForumID);
		exists = false;
		for (int i = 0; i < topics.size(); i++) 
		{
			if(TopicID == topics.elementAt(i).getId());
			exists = true;
		}
		assertTrue(!exists);
	}
	
	
	@Test
	public void testAddModerator()
	{
		init_forum_logout();
		loginSuperAdmin();
		String subforum = addSubForum("Planes" , ForumID , adminID);
		SubForumID = Integer.parseInt(getWord(subforum, 1));
		logout();
		register_login( "max" ,"1234" , ForumID);
		int usr = userID;
		logout();
		
		Vector<Integer> moderators = Reactor.db.getSubForumModerators(SubForumID);
		boolean exists = false;
		for (int i = 0; i < moderators.size(); i++) 
		{
			if(usr == moderators.elementAt(i))
				exists = true;
		}
		assertFalse(exists);
		
		loginSuperAdmin();
		addAdmin(userID , ForumID);
		//logout();
		//admin
		//loginUser("maxi" , "4321" ,ForumID);
		String ans5 = addModerator(userID , SubForumID);
		assertTrue(ans5.startsWith("MODERATOR_ADDED"));
		//logout();
		
		moderators = Reactor.db.getSubForumModerators(SubForumID);
		
		for (int i = 0; i < moderators.size(); i++) 
		{
			if(usr == moderators.elementAt(i))
				exists = true;
		}
		assertTrue(exists);
	}
	
	
	@Test
	public void testRemoveSubForum()
	{
		init_forum_logout();
		loginSuperAdmin();
		String subforum = addSubForum("Planes" , ForumID , adminID);
		SubForumID = Integer.parseInt(getWord(subforum, 1));
		logout();
		
		Vector<SubForum> subForums = Reactor.db.getSubForumslist(ForumID);
		boolean exists = false;
		for (int i = 0; i < subForums.size(); i++) 
		{
			if(SubForumID == subForums.elementAt(i).getId())
				exists = true;
		}
		assertTrue(exists);
		
		register_login("maxi" , "4321" ,ForumID);
		logout();
		
		loginSuperAdmin();
		
		addAdmin(userID , ForumID);
		//logout();
		//admin
		String ans5 = send("REMOVE_SUBFORUM\0"+SubForumID);
		assertTrue(ans5.startsWith("SUBFORUM_REMOVED"));
		logout();
		
		subForums = Reactor.db.getSubForumslist(ForumID);
		exists = false;
		for (int i = 0; i < subForums.size(); i++) 
		{
			if(SubForumID == subForums.elementAt(i).getId())
				exists = true;
		}
		assertFalse(exists);
	}
	
	
	@Test
	public void testRemoveModerator()
	{
		init_forum_logout();
		loginSuperAdmin();
		String subforum = addSubForum("Planes" , ForumID , adminID);
		SubForumID = Integer.parseInt(getWord(subforum, 1));
		logout();
		register_login( "max" ,"1234" , ForumID);
		int usr = userID;
		logout();
		loginSuperAdmin();
		addModerator(usr,SubForumID);
		logout();
		
		Vector<Integer> moderators = Reactor.db.getSubForumModerators(SubForumID);
		boolean exists = false;
		for (int i = 0; i < moderators.size(); i++) 
		{
			if(usr == moderators.elementAt(i))
				exists = true;
		}
		assertTrue(exists);
		
		
		loginSuperAdmin();
		addAdmin(userID , ForumID);
		//logout();
		//admin
		loginUser("maxi" , "4321" ,ForumID);
		String ans5 = removeModerator(usr , SubForumID);
		assertTrue(ans5.startsWith("MODERATOR_REMOVED"));
		logout();
		
		moderators = Reactor.db.getSubForumModerators(SubForumID);
		exists = false;
		for (int i = 0; i < moderators.size(); i++) 
		{
			if(usr == moderators.elementAt(i))
				exists = true;
		}
		assertFalse(exists);
	}
	
	@Test
	public void testNumOfTopicsInSubforum()
	{
		init_forum_logout();
		loginSuperAdmin();
		String subforum = addSubForum("Planes" , ForumID , adminID);
		SubForumID = Integer.parseInt(getWord(subforum, 1));
		String topic = addTopic("hey there","whats up with you?",SubForumID);
		TopicID = Integer.parseInt(getWord(topic, 1));
		logout();
		
		int size = Reactor.db.getSubForumPosts(SubForumID).size();
		//guest
		String ans = send("GET_SUBFORUM_SIZE\0"+SubForumID);
		assertTrue(ans.startsWith("ANS_GET_SUBFORUM_SIZE"));
	
		int num = Integer.parseInt(getWord(ans, 1));
		assertTrue(size == num);
	}
	
	
	@Test
	public void testNumOfPostsOfUser()
	{
		init_forum_logout();
		loginSuperAdmin();
		String subforum = addSubForum("Planes" , ForumID , adminID);
		SubForumID = Integer.parseInt(getWord(subforum, 1));
		logout();
		
		register_login( "max" ,"1234" , ForumID);
		int usr = userID;
		addTopic("well well","what have we here",SubForumID);
		logout();
		
				
		loginSuperAdmin();
		addAdmin(userID , ForumID);
		logout();
		//admin
		loginUser("maxi" , "4321" ,ForumID);
		String ans5 = send("GET_USER_MSGCOUNT\0"+usr);
		assertTrue(ans5.startsWith("ANS_GET_USER_MSGCOUNT"));
		logout();
		
		int size = Reactor.db.getUserPosts(usr).size();
		int num = Integer.parseInt(getWord(ans5, 1));

		assertTrue(size == num);
	}
	
	
	@Test
	public void testNumOfForums()
	{
		init_forum_logout();
		loginSuperAdmin();
		String subforum = addSubForum("Planes" , ForumID , adminID);
		SubForumID = Integer.parseInt(getWord(subforum, 1));
		logout();
		//guest
		String ans = send("GET_FORUM_COUNT");
		assertTrue(ans.startsWith("ANS_GET_FORUM_COUNT"));
		
		int size = Reactor.db.getForumlist().size();
		int num = Integer.parseInt(getWord(ans, 1));

		assertTrue(size == num);
		
	}
	
	
	@Test
	public void testUsersRegisteredToMultipleForums()
	{
		//No permissions.
	}
	
	@Test
	public void testShowForumUsers()
	{
			init_forum_logout();
			loginSuperAdmin();
			String subforum = addSubForum("Planes" , ForumID , adminID);
			SubForumID = Integer.parseInt(getWord(subforum, 1));
			logout();
			
			Vector<Integer> usersIds = ForumSystemImpl.getForumUsers(ForumID);
			
			//guest
			String ans = send("SHOW_FORUM_USERS\0"+ForumID);
			assertTrue(ans.startsWith("ANS_SHOW_FORUM_USERS"));
			
			String[] message= ans.split("\0");
			Vector<Integer> IDs = new Vector<Integer>();
			
			for (int i = 1; i < message.length; i += 2) {
				IDs.add(Integer.parseInt(message[i]));
			}
			
			//each one of the IDs in the returned message exists in the Vector of users of the forum:
			for (int i = 0; i < IDs.size(); i++) {
				boolean exists = false;
				
				for (int j = 0; j < usersIds.size(); j++) {
					if(IDs.elementAt(i) == usersIds.elementAt(j))
						exists = true;
				}
				
				assertTrue(exists);
			}
	}
	
	@Test
	public void testEditReply()
	{
		init_forum_logout();
		loginSuperAdmin();
		String subforum = addSubForum("Planes" , ForumID , adminID);
		SubForumID = Integer.parseInt(getWord(subforum, 1));
		logout();
		
		register_login( "max" ,"1234" , ForumID);
		int usr = userID;
		String top = addTopic("well well","what have we here",SubForumID);
		int topicID = Integer.parseInt(getWord(top,1));
		logout();
		register_login( "sam" ,"5678" , ForumID);
		String rep = addReply("what did you say?" , topicID);
		int replyID = Integer.parseInt(getWord(rep,1));
		logout();
		

		loginUser("sam" ,"5678" ,ForumID);
		String ans2 = editReply("Oh I got you!" , replyID);
		assertTrue(ans2.startsWith("REPLY_EDITED"));
		logout();

		Reply r = Reactor.db.getReplyByID(replyID);
		String content = r.getContent();
		
		assertTrue(content.equals("Oh I got you!"));
	}
	
	@Test
	public void testAddAdmin()
	{
		//No Permissions.
	}
	
	@Test
	public void testEditPost()
	{
		init_forum_logout();
		loginSuperAdmin();
		String subforum = addSubForum("Planes" , ForumID , adminID);
		SubForumID = Integer.parseInt(getWord(subforum, 1));
		logout();
		
		register_login( "max" ,"1234" , ForumID);
		int usr = userID;
		String top = addTopic("well well","what have we here",SubForumID);
		int topicID = Integer.parseInt(getWord(top,1));
		logout();
		register_login( "sam" ,"5678" , ForumID);
		logout();
		
		//user
		loginUser("max" ,"1234" ,ForumID);
		String ans1 = editPost("Oh I got you!" , topicID);
		assertTrue(ans1.startsWith("POST_EDITED"));
		logout();
		
		Post p = Reactor.db.getPostByID(topicID);
		String content = p.getDesc();
		System.out.println("content:"+content);
		assertTrue(content.equals("Oh I got you!"));
	}

	
}